<?php

require_once 'Pipes/Controller/ActionMapper.php';
require_once 'Pipes/FileSystem/Controller/Finder.php';
require_once 'Pipes/FileSystem/Controller/Loader.php';
require_once 'Pipes/FileSystem/File/Finder/AllProjects.php';
require_once 'Pipes/Model/Mapper.php';
require_once 'Pipes/User/AccessControl.php';
require_once 'Pipes/User/AccessControl/Array.php';
require_once 'Pipes/View.php';
require_once 'PipesImpl/Controller.php';
require_once 'PipesImpl/Mixable.php';
require_once 'PipesImpl/Route.php';
require_once 'PipesImpl/User/Credentials.php';

abstract class Pipes_Controller implements PipesImpl_Controller, PipesImpl_Mixable
{
	private $_data = array();
	private $_mixins = array();
	private $_name = '';

	protected $_defaultAction = 'browse';
	protected $_actionMapper = null;
	protected $_config = null;
	protected $_currentCredentials = null;
	protected $_route = null;
	protected $_doAuth = false;

	public function __construct(PipesImpl_Config $config) 
	{
		$explodedName = explode('_', get_class($this));
		$name = substr(array_pop($explodedName), 0, -10);
		
		$this->_name = $name;
		
		
		$this->_actionMapper = new Pipes_Controller_ActionMapper();
		$this->_config = $config;

		$this->_set('isAjax', isset($_GET['isAjax']));

		if ($this->_doAuth === true) {
			$finder = new Pipes_FileSystem_File_Finder_AllProjects($config);
			$permissionFile = $finder->find('permissions.php');
			$this->addMixin(new Pipes_User_AccessControl(
				new Pipes_User_AccessControl_Array(require $permissionFile->fullPath)
			));
		}
	}
	
	/**
	 *
	 * Read-only version of setter that allows any value to be set on 
	 * this controller.
	 *
	 * Generally used for setting internal variables to pass off to wrappers
	 *
	 */
	protected function _set($key, $value) 
	{
		$this->_data[$key] = $value;
	}
	
	public function __set($key, $value) {
		throw new Pipes_Exception('Controller attributes are read-only');
	}

	public function __get($key) 
	{
		return $this->_data[$key];
	}
	
	public function __isset($key) 
	{
		return isset($this->_data[$key]);
	}

	public function getName() 
	{
		return $this->_name;
	}

	public function findExecutable(PipesImpl_Route $route, PipesImpl_User_Credentials $credentials = null) {
		if ($this->_doAuth && !$this->can($credentials, $route)) {
			$loader = new Pipes_FileSystem_Controller_Loader(
				new Pipes_FileSystem_Controller_Finder($this->_config)
			);
			$loader->load('Error');
			$error = new $loader->lastLoaded($this->_config);
			$error->_set('route', $route);
			$error->_set('credentials', $credentials);

			$callback = new Pipes_Value_Callback(array($error, 'actionNotAuthorized'));
			
			return $callback;
		}
		$action = isset($route->action) ? $route->action : $this->_defaultAction;
		$mappedAction = $this->_actionMapper->map($action);
		
		$this->_currentCredentials = $credentials;
		return new Pipes_Value_Callback(array($this, $mappedAction));
	}

	public function addMixin(PipesImpl_Mixin $mixin) {
		$this->_mixins[get_class($mixin)] = $mixin;
	}

	public function __call($method, $arguments) {
		foreach ($this->_mixins as $mixin) {
			if (!method_exists($mixin, $method)) {
				continue;
			}
			return call_user_func_array(array($mixin, $method), $arguments);
		}
	}

	protected function _viewFactory($name) {
		$view = new Pipes_View($this->_config, 'Views/' . $this->getName());
		$view->setName($name);
		$view->controller = $this;
		$view->requestUrl = $_SERVER['REQUEST_URI'];
		return $view;
	}
}

